package com.superbytecode.cloud.common.utils;

import lombok.experimental.UtilityClass;

/**
 * All rights Reserved, Designed By www.super-master.com
 *
 * @ProjectName: beacon-cloud
 * @Package: com.superbytecode.cloud.common.utils
 * @ClassName: FunctionalUtil
 * @Description: [Stream/Lambda/functional异常处理工具类]
 * <p> </p>
 * @Author: [Lance Ting]
 * @Date: 2024/10/22 12:14
 * @Version: V1.0
 * @Copyright: 2024 www.super-master.com Inc. All rights reserved.
 * TODO: 注意,本文件Lance Ting所作,如果转载或使用请标明具体出处!
 **/
@UtilityClass
public class FunctionalUtil {
    /**
     * 确保隐式触发异常，业务区代码不需要显示捕获或抛出异常
     * <p>
     * 如果一段业务代码确保不会抛出所申明的异常，可以使用该方法进行包装，抛出异常
     * <br>
     * ps. new String(bytes, "UTF-8")申明了UnsupportedEncodingException，但编码"UTF-8"是必定不会抛异常的，使用sure进行包装
     * String text = sure(() -> new String(bytes, "UTF-8"))
     * </p>
     * 注： sure方法有一定的风险，因为它隐藏了可能的异常申明，所以请谨慎使用，确保(sure)不会抛出异常才可以使用
     *
     * @param supplier supplier
     * @param <R>      参数类型
     * @param <E>      异常类型
     * @return 包装数据
     */
    public <R, E extends Throwable> R sure(final SupplierWithException<R, E> supplier) {
        try {
            return supplier.get();
        } catch (Throwable exception) {
            throwAsUnchecked(exception);
            // 用来解决在调用方法时提示可能NPE的警告
            throw new UnreachableException();
        }
    }

    /**
     * 无返回值
     *
     * @param runnable runnable
     * @param <E>      异常类型
     */
    public <E extends Throwable> void sure(final RunnableWithException<E> runnable) {
        try {
            runnable.run();
        } catch (Throwable exception) {
            throwAsUnchecked(exception);
            // 用来解决在调用方法时提示可能NPE的警告
            throw new UnreachableException();
        }
    }

    @SuppressWarnings("unchecked")
    private static <E extends Throwable> void throwAsUnchecked(Throwable exception) throws E {
        throw (E) exception;
    }

    // -----------------------------------------------------------------------------------------------------------------
    @FunctionalInterface
    public interface ConsumerWithException<T, E extends Throwable> {
        void accept(T t) throws E;
    }

    @FunctionalInterface
    public interface FunctionWithException<T, R, E extends Throwable> {
        R apply(T t) throws E;
    }

    @FunctionalInterface
    public interface SupplierWithException<T, E extends Throwable> {
        T get() throws E;
    }

    @FunctionalInterface
    public interface PredicateWithException<T, E extends Throwable> {
        boolean test(T t) throws E;
    }

    @FunctionalInterface
    public interface RunnableWithException<E extends Throwable> {
        void run() throws E;
    }

    private class UnreachableException extends RuntimeException {
    }
}